package net.nampham.visioncontrol.view;

import java.nio.FloatBuffer;

import net.nampham.visioncontrol.ILogger;
import net.nampham.visioncontrol.Logger;

import com.javadude.annotation.Bean;
import com.javadude.annotation.Delegate;

import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;

public class MatSingleColor implements IMaterial{

    private final String mVertexShader =
        "uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec4 aColor;\n" +
        "varying vec4 vColor;\n" +        
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vColor = aColor;\n" +
        "}\n";
	
    private final String mFragmentShader =
        "precision mediump float;\n" +
        "varying vec4 vColor;\n" +        
        "void main() {\n" +
        "  gl_FragColor = vColor;\n" +
        //"  gl_FragColor = vec4(1.0,0,0,1.0);\n" +
        "}\n";
    
    private static final int FLOAT_SIZE = 4;
    private static final int VERTICES_STRIDE = 7 * FLOAT_SIZE;
    
    int mProgram;
    int maPositionHandle;
    int maColorHandle;
    int muMVPMatrixHandle;
    //int muColorHandle;
    
    private int loadShader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, source);
            GLES20.glCompileShader(shader);
            int[] compiled = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {
            	Logger.e("Could not compile shader " + shaderType + ":");
            	Logger.e(GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }
    
    private int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }

        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }

        int program = GLES20.glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Logger.e("Could not link program: ");
                Logger.e(GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    private void checkGlError(String op) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
        	Logger.e(op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    public void initialize_once(){
        mProgram = createProgram(mVertexShader, mFragmentShader);
        if (mProgram == 0) {
        	Logger.e("can't compile material");
            return;
        }
        
        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        checkGlError("glGetAttribLocation aPosition");
        if (maPositionHandle == -1) {
        	Logger.e("Could not get attrib location for aPosition");
        }

        maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
        checkGlError("glGetAttribLocation aColor");
        if (maPositionHandle == -1) {
        	Logger.e("Could not get attrib location for aColor");
        }
        
        
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        checkGlError("glGetUniformLocation uMVPMatrix");
        if (muMVPMatrixHandle == -1) {
            Logger.e("Could not get attrib location for uMVPMatrix");
        }
        
        /*
        muColorHandle = GLES20.glGetUniformLocation(mProgram, "uColor");
        checkGlError("glGetUniformLocation muColorHandle");
        if (muColorHandle == -1) {
            Logger.e("Could not get attrib location for muColorHandle");
        }
        */           	
    }

	public void initialize_common() {
        Renderer.getSingleton().use_program(mProgram);
	}


	public void initialize_specific(FloatBuffer buffer) {
		if (Renderer.getSingleton().set_current_buffer(buffer)){
			buffer.position(0);
			GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 
					VERTICES_STRIDE, buffer);
			GLES20.glEnableVertexAttribArray(maPositionHandle);
			buffer.position(3);
			GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 
					VERTICES_STRIDE, buffer);
			checkGlError("glVertexAttribPointer maPositionHandle");
			GLES20.glEnableVertexAttribArray(maColorHandle);
		}
		//GLES20.glUniform4fv(muColorHandle, 4, mColor.v, 0);			
		
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Renderer.getSingleton().get_mvp_matrix(), 0);
	}
	
	RColor mColor = new RColor(1, 0, 0);
	public void setColor(RColor color){
		this.mColor = color;
	}

	public int getVertexStride() {
		return VERTICES_STRIDE;
	};

	public void update(float time) {
		// TODO Auto-generated method stub

	}

	public void dispose() {
		// TODO Auto-generated method stub

	}

}
